iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
Modern Web

為期 30 天的 react 大冒險系列 第 19

react 大冒險-unidirectional flow 單向資料流-day 17-1

  • 分享至 

  • xImage
  •  

在 react 中有個特性稱為 單向資料流 unidirectional flow
簡單說就是 child component 內的資料都來自於 parent component 中的同個 state
在 parent component 中把 state 改變為 props 傳給 child component
達成 所有 child component 的內容都同步於 parent componentparent component 的 state唯一真實資料來源

實做一個 溫度換算器 來解釋這個概念
接收 temperature 後提升 state 到共同的 ancestor component,在 ancestor component 內做運算
再 pass down 回 child component
從輸入數值後發生的一連串過程如下

首先 寫 BoilingVerdict
這個 stateless component 接收 名為 celsius 的 props,顯示出 水是否沸騰

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>水溫已達沸點</p>;
  }
  return <p>水溫未達沸點</p>;
}

接下來寫上層的 Calculator component
Calculator 渲染出 一個 <input /> 輸入 temperature 並將值存在 local state 裡
另外將 temperature 作為 props 傳到 BoilingVerdict 裡

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }

  handleChange(e) {
    this.setState({temperature: e.target.value});
  }

  render() {
    const temperature = this.state.temperature;
    return (
      <fieldset>
        <legend>Enter temperature in Celsius:</legend>
        <input
          value={temperature}
          onChange={this.handleChange} />
        <BoilingVerdict
          celsius={parseFloat(temperature)} />
      </fieldset>
    );
  }
}

這階段對 input 輸入 顯示出水溫是否已達沸點的資訊

將 Calculator component 拆成 兩個 TemperatureInput 分別顯示出華氏及攝氏的值

import React from 'react';

const scaleNames={
    c:'Celsius',
    f:'Fahrenheit'
};

class TempInput extends React.Component{
    constructor (props){
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.state = {
            temperture:''
       }
    }
    // 
    handleChange(e){
        this.setState({temperature : e.target.value});
    }
    render(){
        const {temperature} = this.state;
        const {scale} = this.props;
        return(
        <div>
            <p>輸入 {scaleNames[scale]} 溫度</p>
            <input 
            value={temperature} 
            onChange={this.handleChange} />
        </div>
        )
    }
}

export default TempInput;

Calculator 改寫為

...
return(
            <div>
                <TempInput scale="c" />
                <TempInput scale="f" />
                <BoilComp celsius={temperature}/>
            </div>
        )
...

但這時候兩個 component 的 資料沒有共享,所以輸入其中一個欄位 另一個並不會更新

在 Calcuator 中增加 兩種度數換算的函式 toCelsius / toFahrenheit

// 去掉非數字值,去掉小數點及進位
function tryConvert(temperature, convert) {
  const input = parseFloat(temperature);
  if (Number.isNaN(input)) {
    return "";
  }
  const output = convert(input);
  const rounded = Math.round(output * 1000) / 1000;
  return rounded.toString();
}

// 換算為攝氏
function toCelsius(fahrenheit) {
  return ((fahrenheit - 32) * 5) / 9;
}

// 換算為華氏
function toFahrenheit(celsius) {
  return (celsius * 9) / 5 + 32;
}

上一篇
react 大冒險-form in react-day 16-2
下一篇
react 大冒險-unidirectional flow 單向資料流-day 17-2
系列文
為期 30 天的 react 大冒險30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言